// ============================================================================
//
// Graph framework by Aurelien Moreau aurelien.moreau@gmail.com
// Modified by Pierre CHATEL chatelp@gmail.com
// Distributed under LGPL
// Copyright (C) Aurelien Moreau, 2008, 2009. All rights reserved
//
// ============================================================================

package com.thalesgroup.graphFramework.collections;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

abstract public class AbstractMapList<T, V> extends HashMap<T, List<V>> implements MapList<T,V> {

	private static final long serialVersionUID = 8501750310263006544L;

	public AbstractMapList() {
		super();
	}

	abstract public List<V> createList(int size);
	
	abstract public List<V> createList();
	
	abstract public List<V> createList(List<V> src);
	
	
	public AbstractMapList(final Map<? extends T, ? extends List<V>> m) {
		super(m);
		for (final Map.Entry<T, List<V>> e : entrySet()) {
			final List<V> nl = createList(e.getValue());
			e.setValue(nl);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object clone() {
		final MapList<T, V> clone = (MapList<T, V>) super.clone();
		for (final Map.Entry<T, List<V>> e : clone.entrySet()) {
			final List<V> nl = createList(e.getValue());
			e.setValue(nl);
		}
		return clone;
	}

	public boolean add(final T key, final V value) {
		List<V> list = get(key);
		if (list == null) {
			list = createList(1);
			put(key, list);
		}
		list.add(value);
		return true;
	}

	public boolean remove(final T key, final V value) {
		final List<V> list = get(key);
		if (list == null) {
			return false;
		}
		final boolean present = list.remove(value);

		if (list.isEmpty()) {
			remove(key);
		}

		return present;
	}

	
	public void clusterize(final Iterable<? extends V> set,
			final Accessor<T, V> accessor) {
		clusterize(set.iterator(), accessor);
	}

	public void clusterize(final Iterator<? extends V> i,
			final Accessor<T, V> accessor) {
		for (; i.hasNext();) {
			final V element = i.next();
			final T cluster = accessor.cluster(element);
			add(cluster, element);
		}
	}

	public boolean addAll(final T key, final Collection<? extends V> values) {
		List<V> list = get(key);
		boolean result = false;
		if (list == null) {
			list = createList(values.size());
			put(key, list);
			result = true;
		}
		list.addAll(values);
		return result;
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
	}
}
